// 将传递来的组件 传递到APP.vue中的 teleport 中渲染
import { type AsyncComponentLoader, Teleport } from "vue"
const components = import.meta.glob('@/directive_components/**/index.vue')

// 向组件内部传递数据类型
type ContentType = Record<string,any>
// 指令组件列表
const await_componentList:Record<string,AsyncComponentLoader> = Object.entries(components).reduce((pre,[key,value])=>{
	const isAsync = typeof value === 'function'
	const processedValue = isAsync ? defineAsyncComponent(value as AsyncComponentLoader) : value
	const name = key.split("/").at(-2) as string
	return {
		...pre,
		[name]:processedValue
	}
},{})

// 展示的组件列表
const show_componentList:Ref<Array<{
	key:string,
	ctx?:ContentType
}>> = ref([])

/**
 * 获取 show_componentList
 * 添加组件至body (通常放在App.vue下)
 * @returns <Teleport to="body">....</Teleport>
*/
export const AppendToTeleportBody = defineComponent(
    ()=>{
        return () => {
			const children = show_componentList.value.map((item,index)=>{
				return h(await_componentList[item.key],{
					...(item.ctx || {}),
					unMount:()=>{
						show_componentList.value.splice(index,1)
					}
				})
			})
			return h(Teleport,{
				to:'body'
			},children)
        }
    }
)

/**
 * 向等待渲染组件列表中添加组件
 * @param ins 组件文件
 * @param ctx 向组件内部传递的数据 不传递对象默认包裹在value中
 * @return void
 * @example
   import { showComponent } from '@/utils/index.ts'
   const trigger = showComponent('Confirm',{ name:'hi' })
*/
export const showComponent = (key:string,ctx?:any)=>{
	ctx = ctxProxy(ctx)
	show_componentList.value.push({ key,ctx })
}
/**
 * 使用外部引用的组件进行渲染
 * @param ins 引入的组件文件
 * @param ctx 向组件内部传递的数据 不传递对象默认包裹在value中
 * @return void
 * @example
   import Confirm from '...组件文件'
   import { useComponent } from '@/utils/index.ts'
   const trigger = useComponent(Confirm,{ name:'hi' })
*/
export const useComponent = ( ins:any,ctx?:any )=>{
	const key = ins.__hmrId
	await_componentList[key] = ins
	ctx = ctxProxy(ctx)
	showComponent(key,ctx)
}
/**
 * 不是对象默认包裹value
 * @param ctx 任意数据
 * @return { value:ctx | ...ctx }
*/
function ctxProxy(ctx:any):ContentType{
	return ctx && typeof ctx !== 'object' ? {
		value:ctx
	} : ctx
}